import java.util.*;
import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

//----------------------------------------------------------------------------
//                                INICIO
//                        Itens de persistência
//----------------------------------------------------------------------------
enum Classe { CLIENTE, FITA, LOCACAO;}

class ItemPersistencia implements Serializable {
	protected Classe classe; 
	protected String oid;  //Objeto Identificador; identifica unicamente um
	                       //objeto em todo o sistema
						   
	ItemPersistencia (String oid) {this.oid = oid;}
	Classe getClasse() {return classe;}
	String getOID() {return oid;}
	
}

class Cliente extends ItemPersistencia {
	private String nome, endereco;
	
	public Cliente (String oid) {
		super(oid);
		classe = Classe.CLIENTE;
	}
	
	public void setNome(String n) {nome = n;}
	public String getNome() {return nome;}
	public void setEndereco(String e) {endereco = e;}
	public String getEndereco() {return endereco;}
}

class Fita extends ItemPersistencia {
	private String titulo, genero; //genero-> comedia, romance, etc..
	public Fita(String oid) {
		super(oid);
		classe = Classe.FITA;
	}
	public void setTitulo(String t) {titulo = t;}
	public String getTitulo() {return titulo;}
	public void setGenero(String g) {genero = g;}
	public String getGenero() {return genero;}
	
	}

class Locacao extends ItemPersistencia {
	private String oid_cliente,
	               oid_fita,
				   data;
				   
	public Locacao (String oid, String oidc, String oidf, String d) {
		super(oid);
		oid_cliente = oidc;
		oid_fita = oidf;
		data = d;
		classe = Classe.LOCACAO;
	}
	
	String getClienteOID() { return oid_cliente;}
	String getFitaOID() { return oid_fita;}
	String getData() {return data;}
}



//----------------------------------------------------------------------------
//                                FIM
//                        Itens de persistência
//----------------------------------------------------------------------------

class Iterador { 
	protected  ArrayList<ItemPersistencia> colecao;
	protected int indice;
	
	public Iterador () {
		colecao = new ArrayList<ItemPersistencia>();
		indice = 0;
	}
	public Iterador (ArrayList<ItemPersistencia> arl) {
		colecao = arl;
		indice  = 0 ;
	}
	
	public boolean vazio () { return colecao.isEmpty();}

	public void primeiro() {indice = 0;}

	public void fim() {indice = colecao.size() - 1;}

	public boolean anterior() {
        if (indice > 0) {
           indice--;
           return true;
        }
        return false;
	}

	public boolean proximo() {
		if (indice < (colecao.size()-1)) {
			indice++;
            return true;
        }
        return false;
    }

	public ItemPersistencia obter() {return colecao.get(indice);}

}

class IteradorCliente extends Iterador {
	public IteradorCliente (ArrayList<ItemPersistencia> arl) {super(arl);}
	public IteradorCliente (Iterador it) { colecao = it.colecao;}
	public Cliente obter() {return (Cliente) super.obter();}
}

class IteradorFita extends Iterador {
	public IteradorFita (ArrayList<ItemPersistencia> arl) {super(arl);}
	public IteradorFita (Iterador it) { colecao = it.colecao;}
	public Fita obter() {return (Fita) super.obter();}
}

class IteradorLocacao extends Iterador {
	public IteradorLocacao (ArrayList<ItemPersistencia> arl) {super(arl);}
	public IteradorLocacao (Iterador it) { colecao = it.colecao;}
	public Locacao obter() {return (Locacao) super.obter();}
}


//---------------------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------------------------------

class Serializador {
	String arquivo;
	
	public Serializador (String arq){
		arquivo = arq;
	}
	
	public void cadastrar(ArrayList<ItemPersistencia> arl) {
		try {
			File f = new File(arquivo);
			f.delete();
			f = null;
			
			ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(arquivo));
			for (int i=0; i < arl.size() ; i++ ) {
				out.writeObject((ItemPersistencia) arl.get(i));	
			}
			
			out.close();
		}
		catch (FileNotFoundException e) {}
		catch (IOException e) {}
	}
	
	public void recuperar(ArrayList<ItemPersistencia> arl) {
		arl.clear();
		try {
			ObjectInputStream in = new ObjectInputStream (new FileInputStream(arquivo));
			ItemPersistencia it; ;
			for (int i = 0; (it = (ItemPersistencia) in.readObject()) != null; i++){
				arl.add(it);
			}
			in.close();
		}
		catch (IOException e) {}
		catch (ClassNotFoundException e) {}		
	}
}


abstract class MapaPersistencia {
	protected ArrayList<ItemPersistencia> colecaoObjetos;
	protected int indice;
	protected Serializador armazenamento;
	
	protected boolean haItemPersistido(String oid) {
		boolean resposta = false;
		int i;
		for (i=0; i<colecaoObjetos.size(); i++ ) {
			if(colecaoObjetos.get(i).getOID().equalsIgnoreCase(oid)) {
				resposta = true;
				indice = i;
			}
		}
		return resposta;
	}
	protected abstract void inserirItemNoArmazenamento(ItemPersistencia ip);
	protected abstract void excluirItemNoArmazenamento();
	
	public MapaPersistencia () {
		colecaoObjetos = new ArrayList<ItemPersistencia>();
		armazenamento = null;
		indice = -1;
	}
	
	public boolean inserir(ItemPersistencia ip) {
		boolean resposta = false;
		if(!haItemPersistido(ip.getOID())){
			inserirItemNoArmazenamento(ip);
			resposta = true;
		}
		armazenamento.cadastrar(colecaoObjetos);
		return resposta;
	}
	
	public boolean excluir(String oid){
		boolean resposta = false;
		if(haItemPersistido(oid)){//testa se há o objeto na persistencia
			excluirItemNoArmazenamento();
			resposta = true;
		}
		armazenamento.cadastrar(colecaoObjetos);
		return resposta;
	}
	
	public Iterador getTodos(){ return new Iterador(colecaoObjetos);}
	public ItemPersistencia get(String oid) {
		if( !haItemPersistido(oid)) { return null;}
		return colecaoObjetos.get(indice);
	}
}


class MPCliente extends MapaPersistencia {
	protected void inserirItemNoArmazenamento (ItemPersistencia ip) {
		colecaoObjetos.add(ip);
	}

	protected void excluirItemNoArmazenamento () {
		colecaoObjetos.remove(indice);
	}
		
	public MPCliente () {
		super();
		armazenamento = new Serializador("cliente.dat");
		armazenamento.recuperar(colecaoObjetos);
	}
}

class MPFita extends MapaPersistencia {
	protected void inserirItemNoArmazenamento (ItemPersistencia ip) {
		colecaoObjetos.add(ip);
	}

	protected void excluirItemNoArmazenamento () {
		colecaoObjetos.remove(indice);
	}
	
	public MPFita () {
		super();
		armazenamento = new Serializador("fita.dat");
		armazenamento.recuperar(colecaoObjetos);
	}
}

class MPLocacao extends MapaPersistencia {
	protected void inserirItemNoArmazenamento (ItemPersistencia ip) {
		colecaoObjetos.add(ip);
	}

	protected void excluirItemNoArmazenamento () {
		colecaoObjetos.remove(indice);
	}
	
	public MPLocacao () {
		super();
		armazenamento = new Serializador("locacao.dat");
		armazenamento.recuperar(colecaoObjetos);
	}
}

class Persistencia {
	private Hashtable<Classe, MapaPersistencia> mapeadores;
	private static Persistencia persistencia;
	
	static { persistencia = null; }
	
	private Persistencia () {
		mapeadores = new Hashtable<Classe, MapaPersistencia>();
		mapeadores.put(Classe.CLIENTE, new MPCliente());
		mapeadores.put(Classe.FITA, new MPFita());
		mapeadores.put(Classe.LOCACAO, new MPLocacao());
	}

	public static Persistencia obterInstancia() {
		if( persistencia == null ) {
			persistencia = new Persistencia();
		}

		return persistencia;
	}
	
	public boolean inserir(ItemPersistencia ip) {
		return mapeadores.get(ip.getClasse()).inserir(ip);
	}
	
	public boolean excluir(String oid, Classe classe) {
		return mapeadores.get(classe).excluir(oid);
	}
	
	public Iterador getTodos(Classe classe) {
		return mapeadores.get(classe).getTodos();
	}
	
	public ItemPersistencia obterItemPersistencia(String oid, Classe classe) {
		return mapeadores.get(classe).get(oid);
	}
}

class Controle {
	private Persistencia p;
	private static Controle controle;
	
	static { controle = null; }
	
	private Controle() {
		p = Persistencia.obterInstancia();
	}
	
	public static Controle obterInstancia () {
		if (controle == null ) {
			controle = new Controle();
		}
		return controle;
	}
	
	public boolean inserir(ItemPersistencia ip) {
		return p.inserir(ip);
	}
	
	public boolean excluir(String oid, Classe classe) {
		return p.excluir(oid, classe);
	}
	
	public IteradorCliente getListaClientes() {
		return new IteradorCliente(p.getTodos(Classe.CLIENTE));
	}
	
	public IteradorFita getListaFitas() {
		return new IteradorFita(p.getTodos(Classe.FITA));
	}
	
	public Cliente getCliente(String oid) {
		return (Cliente) p.obterItemPersistencia(oid, Classe.CLIENTE);
	}
	
	public Fita getFita(String oid) {
		return (Fita) p.obterItemPersistencia(oid, Classe.FITA);
	}
}

/*---------------------------------------------------------------------------------------------------------------------------------------------
						INICIO FRONTEIRA
---------------------------------------------------------------------------------------------------------------------------------------------*/

class Formulario extends JFrame {
	protected static int ALTURA = 200;
	protected static int LARGURA = 450;
	protected static int X = 450;
	protected static int Y = 300;
	
	protected JMenuBar menuBar;
	
	protected FormularioCadastro fcliente, ffita;
	
	public Formulario (String titulo) {
		super(titulo);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setSize(LARGURA,ALTURA);
		setLocation(X,Y);
		construirMenu();
		construirFormularioCliente();
		construirFormularioFita();
		setVisible(true);
	}
	
	protected void construirMenu() {
		menuBar = new JMenuBar();
		menuBar.setOpaque(true);
		
		JMenu cadastro = construirMenuCadastro();
		
		menuBar.add(cadastro);
		setJMenuBar(menuBar);
	}
	
	protected JMenu construirMenuCadastro(){
		JMenu cadastro = new JMenu("Cadastro");
		JMenuItem cliente = new JMenuItem("Cliente");
		JMenuItem fita = new JMenuItem("Fita");
		
		cadastro.add(cliente);
		cadastro.add(fita);
		
		return cadastro;
	}
	
	protected void construirFormularioCliente() {
		fcliente = new FormularioCadastro("Cadastro de Cliente");
		fcliente.setCampo("ID",10);
		fcliente.setCampo("Nome",30);
		fcliente.setCampo("Endereco",30);
		fcliente.setBotao("Cadastrar", new AcaoBotaoCliente());
		fcliente.setBotao("Consultar", new AcaoBotaoCliente());
		fcliente.setBotao("Limpar", new AcaoBotaoCliente());
		getContentPane().add(fcliente);
	}
	
	protected void construirFormularioFita() {
		ffita = new FormularioCadastro("Cadastro de Fita");
		ffita.setCampo("ID",10);
		ffita.setCampo("Título",30);
		ffita.setCampo("Gênero",30);
		ffita.setBotao("Cadastrar", new AcaoBotaoFita());
		ffita.setBotao("Consultar", new AcaoBotaoFita());
		ffita.setBotao("Limpar", new AcaoBotaoFita());
		getContentPane().add(ffita);
	}
	
	protected class AcaoBotaoCliente implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			JButton b = (JButton) e.getSource();
			
			if(b.getText().equalsIgnoreCase("Cadastrar")) {
				if (fcliente.getCampo("ID").getText().isEmpty()   ||
					fcliente.getCampo("Nome").getText().isEmpty() ||
					fcliente.getCampo("Endereco").getText().isEmpty() ) { 
					
					JOptionPane.showMessageDialog(fcliente, "Todos os campos são obrigatórios.");
					return;
				}
					
				Cliente c = new Cliente(fcliente.getCampo("ID").getText());
				c.setNome(fcliente.getCampo("Nome").getText());
				c.setEndereco(fcliente.getCampo("Endereco").getText());
				if (! Controle.obterInstancia().inserir(c) ) {
					JOptionPane.showMessageDialog(fcliente, "ID já existe.");
					fcliente.getCampo("ID").setText(null);
					return;
				}
				fcliente.limparCampos();
			}
			if(b.getText().equalsIgnoreCase("Consultar")) {
				if( fcliente.getCampo("ID").getText().isEmpty() ) {
					JOptionPane.showMessageDialog(fcliente, "Preencha ID para consulta.");
					return;
				}
				Cliente c = Controle.obterInstancia().getCliente(fcliente.getCampo("ID").getText());
				if (c == null ) { 
					JOptionPane.showMessageDialog(fcliente, "Cliente não encontrado.");
					return;
				}
				fcliente.getCampo("ID").setText(c.getOID());
				fcliente.getCampo("Nome").setText(c.getNome());
				fcliente.getCampo("Endereco").setText(c.getEndereco());
			}
			if(b.getText().equalsIgnoreCase("Limpar")) {
				fcliente.limparCampos();
			}
		}
	}
	
	protected class AcaoBotaoFita implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			JButton b = (JButton) e.getSource();
			
			if(b.getText().equalsIgnoreCase("Cadastrar")) {
				if (ffita.getCampo("ID").getText().isEmpty()   ||
					ffita.getCampo("Título").getText().isEmpty() ||
					ffita.getCampo("Gênero").getText().isEmpty() ) { 
					
					JOptionPane.showMessageDialog(ffita, "Todos os campos são obrigatórios.");
					return;
				}
					
				Fita f = new Fita(ffita.getCampo("ID").getText());
				f.setTitulo(ffita.getCampo("Título").getText());
				f.setGenero(ffita.getCampo("Gênero").getText());
				if (! Controle.obterInstancia().inserir(f) ) {
					JOptionPane.showMessageDialog(ffita, "ID já existe.");
					ffita.getCampo("ID").setText(null);
					return;
				}
				ffita.limparCampos();
			}
			if(b.getText().equalsIgnoreCase("Consultar")) {
				if( ffita.getCampo("ID").getText().isEmpty() ) {
					JOptionPane.showMessageDialog(ffita, "Preencha ID para consulta.");
					return;
				}
				Fita f = Controle.obterInstancia().getFita(ffita.getCampo("ID").getText());
				if (f == null ) { 
					JOptionPane.showMessageDialog(ffita, "Fita não encontrada.");
					return;
				}
				ffita.getCampo("ID").setText(f.getOID());
				ffita.getCampo("Título").setText(f.getTitulo());
				ffita.getCampo("Gênero").setText(f.getGenero());
			}
			if(b.getText().equalsIgnoreCase("Limpar")) {
				ffita.limparCampos();
			}
		}
	}
}

class FormularioCadastro extends JPanel {
	Hashtable<String, JTextField> tabela_campos;
	JPanel cabecalho, campos, botoes;
	
	public FormularioCadastro (String texto) {
		tabela_campos = new Hashtable<String, JTextField>();
		
		setLayout (new BorderLayout());
		
		JPanel espacador = new JPanel();
		espacador.setLayout(new BoxLayout(espacador, BoxLayout.X_AXIS));
		espacador.add(Box.createHorizontalStrut(10));
		add(espacador, BorderLayout.WEST);
		
		cabecalho = new JPanel();
		cabecalho.setLayout(new BoxLayout(cabecalho, BoxLayout.X_AXIS));
		cabecalho.add(new JLabel(texto));
		cabecalho.add(Box.createHorizontalGlue());
		add(cabecalho, BorderLayout.NORTH);
		
		campos = new JPanel();
		campos.setLayout(new BoxLayout(campos, BoxLayout.Y_AXIS));
		campos.add(Box.createVerticalStrut(30));
		add(campos, BorderLayout.CENTER);
		
		botoes = new JPanel();
		botoes.setLayout(new FlowLayout(FlowLayout.RIGHT));
		add(botoes, BorderLayout.SOUTH);
		
	}

	public void setCampo (String nome, int qde_caracteres) {
		EntradaDados ed = new EntradaDados(nome, qde_caracteres);
		tabela_campos.put(nome,ed.caixa_texto);
		campos.add(ed);
		campos.add(Box.createVerticalStrut(5));
	}
		
	public JTextField getCampo(String nome) {
		return tabela_campos.get(nome);
	}
	
	public void limparCampos() {
		Iterator<JTextField> i = tabela_campos.values().iterator();
						
		while (i.hasNext()) {
			i.next().setText(null);
		}		
	}
	public void setBotao(String texto, ActionListener listener) {
		JButton b = new JButton (texto);
		b.addActionListener(listener);
		botoes.add(b);
	}
	
	protected class EntradaDados extends JPanel {
		public JLabel rotulo;
		public JTextField caixa_texto;
		
		public EntradaDados (String nome, int qde_caracteres) {
			setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
			rotulo = new JLabel(nome);
			caixa_texto = new JTextField(qde_caracteres);
			caixa_texto.setMaximumSize(caixa_texto.getPreferredSize());
			add(rotulo);
			add(caixa_texto);
			add(Box.createHorizontalGlue());
			
		}
		
	}
	
}

/*---------------------------------------------------------------------------------------------------------------------------------------------
						FIM FRONTEIRA
---------------------------------------------------------------------------------------------------------------------------------------------*/

//public class Locadora {
//	public static void main(String args[]) {
//		Formulario aplicacao = new Formulario("Locadora de Video");
//	}
//}